import asyncio
import json

from mini_web import server
from mini_web.request import Request


class MiniWeb:

    def __init__(self):
        self.get_func_map = {}
        self.post_func_map = {}
        self.func_map = {"GET": self.get_func_map, "POST": self.post_func_map}

    def manage_route(self, url, methods, handler):
        if not methods:
            self.get_func_map[url] = handler
        elif type(methods) != list:
            return None
        else:
            for i in methods:
                self.func_map[i][url] = handler

    def route(self, url: str, methods=None, **kwargs):
        """
        route 装饰器，用来装饰加载路由
        """

        def func(handler):
            # 将路由添加到对象属性中
            self.manage_route(url, methods, handler)

            def decorate(*args, **kwargs):
                handler(*args, **kwargs)

            return decorate

        return func

    def run(self, host="127.0.0.1", port=5569):
        print("start: http://{}:{}".format(host, port))
        asyncio.run(server.server(self, host, port))

    async def __call__(self, scope, receive, send):

        assert scope['type'] == 'http'
        method = scope["method"]
        func_map = self.func_map.get(method, None)
        # 判断是否是get post方法
        if func_map is None:
            await send({
                'type': 'http.response.start',
                'status': 405,
                'headers': [
                    [b'content-type', b'text/plan'],
                ]
            })
            await send({
                'type': 'http.response.body',
                'body': b'405 method not find',
            })
        path = scope["path"]

        func = func_map.get(path, None)

        # 如果没有找到路径对应的方法
        if func is None:
            msg = "route is not find"
            # 判断是否是请求方式错误
            if path in self.get_func_map.keys() or path in self.post_func_map:
                msg = " Method not allowed "
            await send({
                'type': 'http.response.start',
                'status': 404,
                'headers': [
                    [b'content-type', b'text/plain'],
                ]
            })
            await send({
                'type': 'http.response.body',
                'body': msg.encode(),
            })
            return

        # 获取参数
        qry_args = {}
        json_data = {}

        # 获取get请求路径参数
        args = scope["query_string"].decode()
        qry_list = args.split("&")
        for i in qry_list:
            data = i.split("=")
            qry_args[data[0]] = data[-1]

        # 如果是post请求
        if method == "POST":
            # 获取post请求中携带的数据
            data = await receive()
            json_data = data["body"].decode()
            if json_data:
                json_data = json.loads(json_data)

        # 构造请求对象
        request = Request(method=method, url=path, args=qry_args, json=json_data)

        # 请求响应
        code = 500
        data = "server error"
        content_type = "text/plan"
        try:
            response = await func(request)
            code = 200
            data = response.response_data
            content_type = response.type
        except Exception as e:
            pass
        await send({
            'type': 'http.response.start',
            'status': code,
            'headers': [
                [b'content-type', content_type.encode()],
            ]
        })
        await send({
            'type': 'http.response.body',
            'body': data.encode(),
        })
